﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace FourKillEnginePrototype
{
    public enum SpriteType
    {
        Person,
        Cloud,
        Vegetation,
        Fixed
    }
    public class Sprite
    {
        private bool _hasMoved = true;
        private double _lastMasterX, _lastMasterY, _lastMasterOrientation;
        private double _x, _y, _z, _orientation;
        private int _movementIndex;
        

        public void Move(double distance)
        {
            LocationX += distance * Math.Cos(OrientationAngle);
            LocationY += distance * Math.Sin(OrientationAngle);

            // Needs to be dynamic.
            _movementIndex = (_movementIndex + 1 > 2) ? 0 : _movementIndex + 1;
        }

        public void TurnDegrees(double degrees)
        {
            OrientationAngle += degrees * Math.PI / 180;
        }

        public Image CurrentImage(int w, int h)
        {
            Bitmap resizedBmp = new Bitmap(w, h);
            if (SpriteSheet != null)
            {
                // draw bitmap
                Bitmap bmp = SpriteSheet.GetImage(this.RelativeOrientation, _movementIndex);
                bmp.MakeTransparent(Color.FromArgb(0, 255, 255));

                if (w > 0 && h > 0)
                {
                    resizedBmp = new Bitmap(w, h);
                    using (Graphics gr = Graphics.FromImage(resizedBmp))
                    {
                        gr.SmoothingMode = SmoothingMode.AntiAlias;
                        gr.InterpolationMode = InterpolationMode.NearestNeighbor;
                        gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
                        gr.DrawImage(bmp, new Rectangle(0, 0, w, h));
                    }
                }
            }
            return resizedBmp;
        }

        public ISimpleSpriteSheet SpriteSheet { get; set; }
        public double Height { get; set; }
        public double Width { get; set; }
        public Color Color { get; set; }
        public double MovementSpeed { get; set; }
        public SpriteType SpriteType { get; set; }
        public byte Alpha { get; set; }

        public double LocationX 
        {
            get { return _x; }
            set { _x = value; _hasMoved = true; }
        }
        public double LocationY
        {
            get { return _y; }
            set { _y = value; _hasMoved = true; }
        }
        public double Levitation
        {
            get { return _z; }
            set { _z = value; _hasMoved = true; }
        }

        public double OrientationAngle
        {
            get { return _orientation; }
            set { _orientation = value; _hasMoved = true; }
        }

        public bool IsBehindPlayer { get; set; }
        public double RelativeX { get; set; }
        public double RelativeY { get; set; }
        public double RelativeAngleToX { get; set; }
        public double RelativeAngle { get; set; }
        public double RelativeOrientation { get; set; }

        public double RelativeAngleToX_degrees { get { return RelativeAngleToX * 180d / Math.PI; } }
        public double RelativeAngle_degrees { get { return RelativeAngle * 180d / Math.PI; } }

        public double RelativeDistance { get; set; }

        public void UpdateRelativeCoordiantes(double x, double y, double orientation)
        {
            //TODO: if sprite coordinates change as well, of course. Need properties that set a flag or something.
            if (_hasMoved || _lastMasterX != x || _lastMasterY != y || _lastMasterOrientation != orientation)
            {
                _lastMasterX = x;
                _lastMasterY = y;
                _lastMasterOrientation = orientation;

                double translatedX = (LocationX - x),
                    translatedY = (LocationY - y),
                    reverseOrientation = -1 * orientation;

                RelativeX = (Math.Cos(reverseOrientation) * translatedX) - (Math.Sin(reverseOrientation) * translatedY);
                RelativeY = (Math.Sin(reverseOrientation) * translatedX) + (Math.Cos(reverseOrientation) * translatedY);

                RelativeAngleToX = Math.Atan2(Math.Abs(RelativeY), Math.Abs(RelativeX)) * (RelativeX > 0 && RelativeY < 0 ? -1d : 1d);
                if (RelativeX < 0 && RelativeY < 0) RelativeAngle = Math.Abs(RelativeAngleToX) + Math.PI;
                else if (RelativeX > 0 && RelativeY < 0) RelativeAngle = 2 * Math.PI - Math.Abs(RelativeAngleToX);
                else if (RelativeX < 0 && RelativeY > 0) RelativeAngle = Math.PI - Math.Abs(RelativeAngleToX);

                RelativeOrientation = this.OrientationAngle - orientation;
                if (RelativeOrientation < 0) RelativeOrientation = (Math.PI * 2) + RelativeOrientation;
                RelativeOrientation = RelativeOrientation > (Math.PI * 2) ? RelativeOrientation % (Math.PI * 2) : RelativeOrientation;

                IsBehindPlayer = RelativeX <= 0;
                RelativeDistance = Math.Sqrt(Math.Pow(RelativeX, 2) + Math.Pow(RelativeY, 2));
                _hasMoved = false;
            }
        }
    }
}
